#include "MephistoCAM.h"

extern SockInfo infos[16];
extern int global_abort_exposure;

void *serverForClient(void *arg) {
    
    //////////////////////////////////////////////////////////
    // necessay info recived from LabView ICS

    char tag[16];

    int fout_name_is_ready = 0;
    char fout_name[128];

    int exp_t_is_ready = 0;
    double exp_t = -1;

    int img_is_dark = 0;
    //////////////////////////////////////////////////////////

    SockInfo           *pinfo  = (SockInfo*)arg;
    MephistoCAM_Config *mcfg   = pinfo->mcfg;
    
    char recvbuf[1024];
    char sendbuf[1024];

    int new_fd = pinfo->fd;
    char ip[32];

    while(1) {
        
        bzero(recvbuf, sizeof(recvbuf));
        bzero(sendbuf, sizeof(sendbuf));

        // print client IP/port
        fprintf(stdout, "Client IP: %s, port: %d ==> ",
            inet_ntop(AF_INET, &pinfo->addr.sin_addr.s_addr, ip, sizeof(ip)),
            ntohs(pinfo->addr.sin_port));

        socklen_t len = recv(new_fd, recvbuf, sizeof(recvbuf), 0);

        if( len > 0 ){
            // fputs(recvbuf,stdout);
            fprintf(stdout, "%s\n", recvbuf);

            if( strcmp(recvbuf, "exposure") == 0 ){
                
                strcpy(sendbuf, "expostarted");
                send(new_fd, sendbuf, strlen(sendbuf), 0);

                if( (1 == fout_name_is_ready) && (1 == exp_t_is_ready) ){

                #if defined(_ENABLE_PINNING_BEFORE_EXPOSURE_)
                    fprintf(stdout, "[CCD_PINNING] --> start\n");
                    socket_pinning( mcfg->gpio_out, 1 );
                    usleep(200000); // 200ms
                    socket_pinning( mcfg->gpio_out, 0 );
                    fprintf(stdout, "[CCD_PINNING] --> finish\n");
                #endif

                #if defined(_ENABLE_REFRESH_BEFORE_EXPOSURE_)

                    int htrans_num_bak = mcfg->config_ccd_drive->htrans_num;
                    mcfg->config_ccd_drive->htrans_num = 1;

                    // set htrans_num to 1
                    socket_config_ccd_drive(mcfg, 
                                            mcfg->gpio_flt_ctrl, 
                                            mcfg->gpio_flt_data,
                                            mcfg->gpio_in,
                                            mcfg->gpio_pl_ps,
                                            mcfg->gpio_out,
                                            mcfg->gpio_out2,
                                            mcfg->gpio_spi_ps_ctrl,
                                            mcfg->gpio_spi_ps_data );

                    fprintf(stdout, "[CCD_DRIVE] set to fast refresh mode.\n");

                    // fast refresh
                    ccd_refresh( mcfg->gpio_out, 
                                 mcfg->gpio_in, 
                                 mcfg->gpio_pl_ps, 
                                 mcfg->n_row,
                                 mcfg->n_col,
                                 mcfg->n_bytes,
                                 0,
                                 "" );

                    mcfg->config_ccd_drive->htrans_num = htrans_num_bak;

                    // reset htrans_num
                    socket_config_ccd_drive(mcfg, 
                                            mcfg->gpio_flt_ctrl, 
                                            mcfg->gpio_flt_data,
                                            mcfg->gpio_in,
                                            mcfg->gpio_pl_ps,
                                            mcfg->gpio_out,
                                            mcfg->gpio_out2,
                                            mcfg->gpio_spi_ps_ctrl,
                                            mcfg->gpio_spi_ps_data );

                    fprintf(stdout, "[CCD_DRIVE] reset to nomal readout mode.\n");

                #endif
                    
                    ccd_exposure_with_abort(exp_t, 
                                            mcfg->gpio_out, 
                                            mcfg->gpio_in, 
                                            mcfg->gpio_pl_ps, 
                                            mcfg->n_row,
                                            mcfg->n_col,
                                            mcfg->n_bytes,
                                            0,
                                            img_is_dark,
                                            fout_name,
                                            mcfg->log_shutter_fname,
                                            mcfg->log_camera_fname,
                                            global_abort_exposure );

                    if( global_abort_exposure == 1 ){
                        strcpy(sendbuf, "readoutdone");
                        fprintf(stdout, "> sent expoaborted\n");     // 曝光终止
                    } else {
                        strcpy(sendbuf, "readoutdone");
                        fprintf(stdout, "> sent expostarted\n");     // 曝光正常结束
                    }

                    send(new_fd, sendbuf, strlen(sendbuf), 0);
                    exp_t_is_ready  = 0;
                    img_is_dark     = 0;
                } else {
                    fprintf(stdout, "> fout_name is not ready, exposure will no be executed ...\n");
                }
            }
            else if( strcmp(recvbuf, "powerup") == 0 ){
                // socket_power_up(    mcfg, 
                //                     gpio_flt_ctrl, 
                //                     gpio_flt_data,
                //                     gpio_in,
                //                     gpio_pl_ps,
                //                     gpio_out,
                //                     gpio_out2,
                //                     gpio_spi_ps_ctrl,
                //                     gpio_spi_ps_data );

                sleep(1);

                strcpy(sendbuf, "powerup_ok_");
                send(new_fd, sendbuf, strlen(sendbuf), 0);
            }
            else if( strcmp(recvbuf, "powerdown") == 0 ){
                // socket_power_down(  mcfg, 
                //                     gpio_flt_ctrl, 
                //                     gpio_flt_data,
                //                     gpio_in,
                //                     gpio_pl_ps,
                //                     gpio_out,
                //                     gpio_out2,
                //                     gpio_spi_ps_ctrl,
                //                     gpio_spi_ps_data );

                sleep(1);

                strcpy(sendbuf, "powerdownok");
                send(new_fd, sendbuf, strlen(sendbuf), 0);
            }
            else if( strcmp(recvbuf, "imgisdark") == 0 ){
                // not implemented yet ...
                img_is_dark = 1;
                strcpy(sendbuf, "dakreceived");
                send(new_fd, sendbuf, strlen(sendbuf), 0);
                fprintf(stdout, "> sent dakreceived\n");
            }
            else if( strcmp(recvbuf, "imgnodark") == 0 ){
                // not implemented yet ...
                img_is_dark = 0;
                strcpy(sendbuf, "dakreceived");
                send(new_fd, sendbuf, strlen(sendbuf), 0);
                fprintf(stdout, "> sent dakreceived\n");
            }
            else if( strlen(recvbuf) == 9 ){

                fprintf(stdout, "[SoC Socket server] received tag: %s\n", recvbuf);
                sprintf(tag, "%s", recvbuf);
                fprintf(stdout, "[server] len(recvbuf) = %u\n", strlen(recvbuf));

                int isExpTime = isExpTimeTag( tag );

                if( 1 == isExpTime ){
                    exp_t = extractExpTime( tag );
                    fprintf(stdout, "> recieved a exposure time tag, and exp_t = %10.5f\n", exp_t);
                    exp_t_is_ready = 1;
                    strcpy(sendbuf, "expreceived");
                } else {
                    fprintf(stdout, "> recieved a date tag.\n");
                    sprintf(fout_name, "tmp/%s.bin", recvbuf);
                    fout_name_is_ready = 1;
                    strcpy(sendbuf, "tagreceived");
                }
                
                send(new_fd, sendbuf, strlen(sendbuf), 0);
                fprintf(stdout, "> sent %s\n", sendbuf);
                // tag_is_ready = 1;
            }
            else if( strcmp(recvbuf, "abortexp") == 0 ){
                // abort exposure ...
                abortExposure(arg);
                strcpy(sendbuf, "abtreceived");
                send(new_fd, sendbuf, strlen(sendbuf), 0);
                fprintf(stdout, "> sent %s\n", sendbuf);
            }
            else if( strcmp(recvbuf, "exit") == 0 ){

                strcpy(sendbuf, "exit_ok");
                send(new_fd, sendbuf, strlen(sendbuf), 0);
                break;
            }

        }
    }

    close(pinfo->fd);
    pinfo->fd   = -1;
    pinfo->mcfg = NULL;

    close(new_fd);

    return NULL;
}


void abortExposure(void *arg){
    pthread_t ctid = pthread_self();
    global_abort_exposure = 1;
    fprintf(stdout, "[THREAD: %lu] send 'ABORT EXPOSURE' signal!\n", ctid);
}

